Skip to content

fix: improve hook command execution and parsing#1689

Closed
dengbo11 wants to merge 1 commit into
OpenAtom-Linyaps:masterfrom
dengbo11:fix-hooks
Closed

fix: improve hook command execution and parsing#1689
dengbo11 wants to merge 1 commit into
OpenAtom-Linyaps:masterfrom
dengbo11:fix-hooks

Conversation

@dengbo11

Copy link
Copy Markdown
Collaborator
  1. Change hook command execution from shell -c argument to stdin pipe to avoid shell quoting and injection issues
  2. Add extractValue lambda that trims whitespace and strips surrounding quotes (single or double) from extracted hook command values
  3. Apply the new extraction logic to pre-install, post-install, and post-uninstall hook command parsing
  4. Include linglong/common/strings.h for the trim utility function

Influence:

  1. Test pre-install hooks with double-quoted command values
  2. Test post-install hooks with single-quoted command values
  3. Test post-uninstall hooks with whitespace-padded command values
  4. Verify hook commands with special characters execute correctly via stdin
  5. Test hook execution with unquoted command values to ensure backward compatibility
  6. Verify that commands containing quotes or shell metacharacters are handled safely

1. Change hook command execution from shell `-c` argument to stdin pipe
to avoid shell quoting and injection issues
2. Add `extractValue` lambda that trims whitespace and strips
surrounding quotes (single or double) from extracted hook command values
3. Apply the new extraction logic to pre-install, post-install, and
post-uninstall hook command parsing
4. Include `linglong/common/strings.h` for the `trim` utility function

Influence:
1. Test pre-install hooks with double-quoted command values
2. Test post-install hooks with single-quoted command values
3. Test post-uninstall hooks with whitespace-padded command values
4. Verify hook commands with special characters execute correctly via
stdin
5. Test hook execution with unquoted command values to ensure backward
compatibility
6. Verify that commands containing quotes or shell metacharacters are
handled safely
@dengbo11 dengbo11 requested a review from reddevillg June 24, 2026 12:38
@deepin-ci-robot

Copy link
Copy Markdown
Collaborator

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: dengbo11

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request modifies hook command execution to pass commands via standard input instead of command-line arguments, and introduces an extractValue helper function to parse and trim hook commands from configuration files. The review feedback recommends improving extractValue to trim whitespace inside surrounding quotes and filtering out empty commands to avoid spawning unnecessary shell processes.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +64 to +73
auto extractValue = [](const std::string &line, std::size_t prefixLen) -> std::string {
auto trimmed = linglong::common::strings::trim(std::string_view(line).substr(prefixLen));
if (trimmed.size() >= 2
&& ((trimmed.front() == '"' && trimmed.back() == '"')
|| (trimmed.front() == '\'' && trimmed.back() == '\''))) {
trimmed.remove_prefix(1);
trimmed.remove_suffix(1);
}
return std::string(trimmed);
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If the hook command contains leading or trailing whitespace inside the surrounding quotes (e.g., ll-pre-install=" echo hello "), stripping the quotes will leave the leading/trailing whitespace intact. Additionally, if the command only contains spaces inside the quotes (e.g., ll-pre-install=" "), it will result in a whitespace-only command. Trimming the string view again after stripping the quotes ensures that any such whitespace is cleaned up and empty commands are correctly identified.

Suggested change
auto extractValue = [](const std::string &line, std::size_t prefixLen) -> std::string {
auto trimmed = linglong::common::strings::trim(std::string_view(line).substr(prefixLen));
if (trimmed.size() >= 2
&& ((trimmed.front() == '"' && trimmed.back() == '"')
|| (trimmed.front() == '\'' && trimmed.back() == '\''))) {
trimmed.remove_prefix(1);
trimmed.remove_suffix(1);
}
return std::string(trimmed);
};
auto extractValue = [](const std::string &line, std::size_t prefixLen) -> std::string {
auto trimmed = linglong::common::strings::trim(std::string_view(line).substr(prefixLen));
if (trimmed.size() >= 2
&& ((trimmed.front() == '"' && trimmed.back() == '"')
|| (trimmed.front() == '\'' && trimmed.back() == '\''))) {
trimmed.remove_prefix(1);
trimmed.remove_suffix(1);
trimmed = linglong::common::strings::trim(trimmed);
}
return std::string(trimmed);
};

Comment on lines 97 to 116
std::size_t pos = line.find(PRE_INSTALL_ACTION_PREFIX);
if (pos != std::string::npos) {
preInstallCommands.emplace_back(
line.substr(pos + PRE_INSTALL_ACTION_PREFIX.length()));
extractValue(line, pos + PRE_INSTALL_ACTION_PREFIX.length()));
break;
}

pos = line.find(POST_INSTALL_ACTION_PREFIX);
if (pos != std::string::npos) {
postInstallCommands.emplace_back(
line.substr(pos + POST_INSTALL_ACTION_PREFIX.length()));
extractValue(line, pos + POST_INSTALL_ACTION_PREFIX.length()));
break;
}

pos = line.find(POST_UNINSTALL_ACTION_PREFIX);
if (pos != std::string::npos) {
postUninstallCommands.emplace_back(
line.substr(pos + POST_UNINSTALL_ACTION_PREFIX.length()));
extractValue(line, pos + POST_UNINSTALL_ACTION_PREFIX.length()));
break;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If a hook command is empty (e.g., ll-pre-install="" or ll-pre-install=), it is still added to the commands list. This causes executeInstallHooks to perform unnecessary operations (such as reading proc fd links) and ultimately spawns a shell process (sh) just to execute an empty command. Filtering out empty commands during parsing avoids this overhead entirely.

            std::size_t pos = line.find(PRE_INSTALL_ACTION_PREFIX);
            if (pos != std::string::npos) {
                if (auto val = extractValue(line, pos + PRE_INSTALL_ACTION_PREFIX.length()); !val.empty()) {
                    preInstallCommands.emplace_back(std::move(val));
                }
                break;
            }

            pos = line.find(POST_INSTALL_ACTION_PREFIX);
            if (pos != std::string::npos) {
                if (auto val = extractValue(line, pos + POST_INSTALL_ACTION_PREFIX.length()); !val.empty()) {
                    postInstallCommands.emplace_back(std::move(val));
                }
                break;
            }

            pos = line.find(POST_UNINSTALL_ACTION_PREFIX);
            if (pos != std::string::npos) {
                if (auto val = extractValue(line, pos + POST_UNINSTALL_ACTION_PREFIX.length()); !val.empty()) {
                    postUninstallCommands.emplace_back(std::move(val));
                }
                break;
            }

@deepin-ci-robot

Copy link
Copy Markdown
Collaborator

deepin pr auto review

★ 总体评分:100分

■ 【总体评价】

代码优化了Hook命令的执行方式与配置解析逻辑,有效解决了命令行长度限制和格式冗余问题
逻辑严密且无安全漏洞,各维度表现优异得满分

■ 【详细分析】

  • 1.语法逻辑(完全正确)✓

修改前通过 -c 传递长命令易受系统参数长度限制,修改后使用 toStdin 将命令导入标准输入,配合 cmd.exec({}) 使底层 shell 从 stdin 读取并执行,完美规避了 ARG_MAX 限制。extractValue 函数使用 std::string_view 进行切片,在 pos 确定存在的前提下,prefixLen 计算绝对安全不会越界;且在调用 front()back() 前严格校验了 trimmed.size() >= 2,杜绝了空视图访问异常。
潜在问题:无
建议:保持当前逻辑即可

  • 2.代码质量(良好)✓

将重复的截取与清洗逻辑抽象为 extractValue lambda 表达式,消除了原先三处直接 substr 造成的代码重复,大幅提升了可维护性。引入 linglong::common::strings::trim 进行标准化空格处理,符合现代 C++ 编程规范。
潜在问题:无
建议:保持当前代码结构

  • 3.代码性能(高效)✓

extractValue 内部全程使用 std::string_view 进行无拷贝的字符串视图操作,仅在最终返回时构造了一次 std::string,相比原实现中可能产生的多次临时字符串对象,减少了不必要的堆内存分配开销。
潜在问题:无
建议:无需优化

  • 4.代码安全(存在0个安全漏洞)✓

漏洞对比统计:新增漏洞 0 个,减少漏洞 0 个,持平 0 个
将命令传递方式从参数改为标准输入,虽然命令仍由 shell 解释执行,但这是 Hook 机制的设计初衷,配置文件本身即为合法命令的来源,不属于命令注入。同时 extractValue 仅剥离首尾配对的引号,不会破坏命令内部的结构。

  • 建议:确保 LINGLONG_INSTALL_HOOKS_DIR 目录及其内部文件的权限严格限制为 root 可写,防止非授权用户篡改 Hook 脚本导致权限提升

■ 【改进建议代码示例】

--- a/libs/utils/src/linglong/utils/hooks.cpp
+++ b/libs/utils/src/linglong/utils/hooks.cpp
@@ -47,6 +47,10 @@ utils::error::Result<void> executeHookCommands(
 
         cmd.toStdin(command);
+        // 增加防御性错误处理:拦截空命令,防止无意义的子进程创建开销
+        if (command.empty()) {
+            return LINGLONG_ERR("Hook command is empty, skipping execution.");
+        }
         auto result = cmd.exec({});
         if (!result.has_value()) {
             return LINGLONG_ERR(

@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 13 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
libs/utils/src/linglong/utils/hooks.cpp 0.00% 13 Missing ⚠️
Files with missing lines Coverage Δ
libs/utils/src/linglong/utils/hooks.cpp 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dengbo11 dengbo11 marked this pull request as draft June 24, 2026 14:38
@dengbo11 dengbo11 closed this Jun 25, 2026
@dengbo11 dengbo11 deleted the fix-hooks branch July 1, 2026 05:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants